home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / util / wb / WBTitle13d.lha / WBTitle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-12  |  13.7 KB  |  555 lines

  1. /*
  2.  * WBTitle
  3.  *
  4.  * Version 1.3d
  5.  *
  6.  * v1.0   original public release by Mark Thomas
  7.  * v1.3d  German locale version by Martin Kaim (Gwardar), fixes/features:
  8.  * - removed a bug in the numeric display routine ( would print e.g. 10,274,380 as
  9.  *   :,274,380 )
  10.  * - now ToolType SEPARATOR is spelled correctly (instead of SEPERATOR),
  11.  *   also the default separator for German locale now is '.' instead of ','
  12.  * - supplied smakefile
  13.  * - version now works with the German locale (ONLY) (different Workbench title bar)
  14.  *   (can/must be adjusted to any other locale by slight changes in the source and
  15.  *   recompiling)
  16.  * - supplied Icon with a nice tooltype setting (in German only)
  17.  * - adjusted documentation to reflect these changes
  18.  *
  19.  * Public Domain Software
  20.  *
  21.  * This program replaces the Amiga's Workbench title bar so that it shows the amount
  22.  * of all types of FREE memory currently available: Chip, Fast, Public; 
  23.  * further VMM (if installed and ACTIVE), and Retina Gfx board memory (if applicable).
  24.  */
  25.  
  26. #include <string.h>
  27. #include <ctype.h>
  28.  
  29. #include <exec/types.h>
  30. #include <exec/memory.h>
  31. #include <intuition/intuition.h>
  32. #include <dos/dos.h>
  33.  
  34. #include <proto/exec.h>
  35. #include <proto/intuition.h>
  36. #include <proto/dos.h>
  37. #include <proto/retina.h>
  38.  
  39. // Gwardar begin
  40. //#include <proto/vmm.h>
  41. #include <pragmas/retina_pragmas.h>
  42. // Gwardar end
  43.  
  44. #include <clib/alib_protos.h>
  45.  
  46. // The SetWindowTitles function offset
  47. #define SWTOffset -276
  48.  
  49. enum {
  50.     JMPINSTR = 0x4ef9
  51. };
  52.  
  53. typedef struct JmpEntry {
  54.     UWORD Instr;
  55.     APTR Func;
  56. } JmpEntry;
  57.  
  58. static BOOL Replace(void);
  59. static void Restore(void);
  60. static void __asm new_SetWindowTitles(register __a0 struct Window *,
  61.                                 register __a1 UBYTE *, register __a2 UBYTE *,
  62.                                 register __a6 struct Library *);
  63. static void NumberToString(ULONG number);
  64. static void format_number(ULONG number);
  65. static void no_lead_triple(ULONG number);
  66. static void lead_triple(ULONG number);
  67.  
  68. // Gwardar begin
  69. //ULONG AvailVMem(ULONG);
  70. //ULONG Retina_AvailMem(ULONG);
  71. // Gwardar end
  72.  
  73. // Global variables
  74. struct RetinaBase *RetinaBase;
  75. struct Library *VMMBase;
  76.  
  77. // Local variables
  78. static char verstring[] = "$VER: WBTitle 1.3d (enhanced by Gwardar) " __AMIGADATE__;
  79. static char port_name[] = "WBTitle";
  80.  
  81. static void __asm (*old_SetWindowTitles)(register __a0 struct Window *,
  82.                                     register __a1 UBYTE *,
  83.                                     register __a2 UBYTE *,
  84.                                     register __a6 struct Library *);
  85. static JmpEntry *SWTEntry;
  86. static char *chip_str, *fast_str, *public_str, *total_str, *virtual_str;
  87. static char *retina_str, *memorder_str, *prefix_str, *suffix_str, *labels_str;
  88. static char *comma_str, *mem_str, *last_str, *buff_ptr;
  89. static char num_buf[14], comma;
  90. static int units, num_size, mem_str_len, prefix_str_len;
  91. static BOOL sep1000, labels_after;
  92.  
  93. /*
  94.  * The main method for replacing an Amiga OS function as safe as
  95.  * possible is to place the function with a jump table that is
  96.  * allocated.  While the function is replaced, the jump table simply
  97.  * jumps to my routine:
  98.  *
  99.  * jmp  _new_SetWindowTitles
  100.  *
  101.  * When the user asks the program to quit, we can't simply put the
  102.  * pointer back that SetFunction() gives us since someone else might
  103.  * have replaced the function.  So, we first see if the pointer we
  104.  * get back points to the out jump table.  If so, then we _can_ put
  105.  * the pointer back like normal (no one has replaced the function
  106.  * while we has it replaced).  But if the pointer isn't mine, then
  107.  * we have to replace the jump table function pointer to the old
  108.  * function pointer:
  109.  *
  110.  * jmp  _old_SetWindowTitles
  111.  *
  112.  * Finally, we only deallocate the jump table _if_ we did not have
  113.  * to change the jump table.
  114.  */
  115.  
  116. main(int argc, char *argv[])
  117. {
  118.     struct MsgPort *port;
  119.  
  120.     // FindPort() Forbid()
  121.     Forbid();
  122.  
  123.     port = FindPort(port_name);
  124.     if (port) {
  125.         struct MsgPort *reply_port;
  126.  
  127.         // Create a reply port
  128.         reply_port = CreateMsgPort();
  129.         if (reply_port) {
  130.             struct Message msg;
  131.  
  132.             // Set fields in message structure
  133.             msg.mn_ReplyPort = reply_port;
  134.             msg.mn_Length = sizeof(struct Message);
  135.  
  136.             // Send the message
  137.             PutMsg(port, &msg);
  138.  
  139.             // Finished with port, so stop FindPort() Forbid()
  140.             Permit();
  141.  
  142.             // Wait for a reply
  143.             do {
  144.                 WaitPort(reply_port);
  145.             } while (GetMsg(reply_port) == NULL);
  146.  
  147.             // Clear and Delete reply_port Forbid()
  148.             Forbid();
  149.  
  150.             // Clear any messages
  151.             while (GetMsg(reply_port));
  152.  
  153.             // Delete the reply port
  154.             DeleteMsgPort(reply_port);
  155.  
  156.             // Clear and Delete reply_port stop Forbid()
  157.             Permit();
  158.         } else {
  159.             // Finished with port, so stop FindPort() Forbid()
  160.             Permit();
  161.         }
  162.     } else if (port = CreateMsgPort()) {
  163.         struct Message *msg;
  164.         char **ttypes;
  165.  
  166.         // Finished with port, so stop FindPort() Forbid()
  167.         Permit();
  168.  
  169.         // Setup quitting port
  170.         port->mp_Node.ln_Name = port_name;
  171.         port->mp_Node.ln_Pri = -120;
  172.  
  173.         // Add quitting port to public list
  174.         AddPort(port);
  175.  
  176.         // Open the Retina library
  177.         RetinaBase = (struct RetinaBase *)OpenLibrary("retina.library", 0);
  178.  
  179.         // Check on VMM; look for port, and alloc signal
  180.         if (FindPort("VMM_Port")) {
  181.             VMMBase = OpenLibrary("vmm.library", 0);
  182.         }
  183.  
  184.         // Setup to read some arguments
  185.         ttypes = ArgArrayInit(argc, argv);
  186.  
  187.         // Read some arguments
  188.         prefix_str = ArgString(ttypes, "PREFIX", "Amiga Workbench  ");
  189.         suffix_str = ArgString(ttypes, "SUFFIX", "");
  190.         labels_str = ArgString(ttypes, "LABELS", "AFTER");
  191.  
  192.         chip_str = ArgString(ttypes, "CHIP", " Chip  ");
  193.         fast_str = ArgString(ttypes, "FAST", " Fast  ");
  194.         public_str = ArgString(ttypes, "PUBLIC", " Public  ");
  195.         total_str = ArgString(ttypes, "TOTAL", " Total  ");
  196.         virtual_str = ArgString(ttypes, "VIRTUAL", " Virtual  ");
  197.         retina_str = ArgString(ttypes, "RETINA", " Retina  ");
  198.  
  199.         memorder_str = ArgString(ttypes, "MEMORDER", "CVPR");
  200.         sep1000 = (ArgString(ttypes, "THOUSANDSEP", NULL) != NULL);
  201.         units = ArgInt(ttypes, "UNITS", 1);
  202.         comma_str = ArgString(ttypes, "SEPARATOR", NULL);
  203.         if (comma_str && comma_str[0]) {
  204.             comma = comma_str[0];
  205.         } else {
  206.             comma = '.';   // changed from ',' by Gwardar for German locale
  207.                                        // change this back to '.' for English locale 
  208.         }
  209.  
  210.         labels_after = (stricmp(labels_str, "BEFORE") != 0);
  211.         if (units < 0) {
  212.             units = 1;
  213.         }
  214.  
  215.         // Compute the size of numbers
  216.         {
  217.             ULONG maxnum = 0xffffffff;
  218.  
  219.             // Compute the number of digits
  220.             maxnum /= units;
  221.             while (maxnum) {
  222.                 maxnum /= 10;
  223.                 num_size++;
  224.             }
  225.  
  226.             // Compute the number of commas
  227.             if (sep1000) {
  228.                 int com = num_size;
  229.                 while (com > 3) {
  230.                     num_size++;
  231.                     com -= 3;
  232.                 }
  233.             }
  234.         }
  235.  
  236.         // Compute the size of the mem string
  237.         {
  238.             ULONG i = 0;
  239.             char ch;
  240.  
  241.             // Add in the prefix string size
  242.             mem_str_len = prefix_str_len = strlen(prefix_str);
  243.  
  244.             // Add in the memory parts
  245.             while (ch = toupper(memorder_str[i])) {
  246.                 switch (ch) {
  247.                     case 'C':
  248.                         mem_str_len += strlen(chip_str) + num_size;
  249.                         break;
  250.                     case 'F':
  251.                         mem_str_len += strlen(fast_str) + num_size;
  252.                         break;
  253.                     case 'P':
  254.                         mem_str_len += strlen(public_str) + num_size;
  255.                         break;
  256.                     case 'T':
  257.                         mem_str_len += strlen(total_str) + num_size;
  258.                         break;
  259.                     case 'V':
  260.                         if (VMMBase) {
  261.                             mem_str_len += strlen(virtual_str) + num_size;
  262.                         }
  263.                         break;
  264.                     case 'R':
  265.                         if (RetinaBase) {
  266.                             mem_str_len += strlen(retina_str) + num_size;
  267.                         }
  268.                         break;
  269.                 }
  270.                 i++;
  271.             }
  272.  
  273.             // Add in the suffix string size
  274.             mem_str_len += strlen(suffix_str);
  275.         }
  276.  
  277.         if (mem_str_len > 0) {
  278.             // Allocate the memory
  279.             mem_str = AllocMem(mem_str_len + 1, MEMF_PUBLIC);
  280.             if (mem_str) {
  281.                 strcpy(mem_str, prefix_str);
  282.                 last_str = &mem_str[prefix_str_len];
  283.  
  284.                 // Attempt to replace function
  285.                 if (Replace()) {
  286.                     // Wait for someone to signal me to quit
  287.                     do {
  288.                         WaitPort(port);
  289.                         msg = GetMsg(port);
  290.                     } while (msg == NULL);
  291.                     ReplyMsg(msg);
  292.  
  293.                     // Restore function
  294.                     Restore();
  295.                 }
  296.                 FreeMem(mem_str, mem_str_len + 1);
  297.             }
  298.         }
  299.  
  300.         // Cleanup from reading arguments
  301.         ArgArrayDone();
  302.  
  303.         // Remove port from public access
  304.         RemPort(port);
  305.  
  306.         // Clear and Delete port Forbid()
  307.         Forbid();
  308.  
  309.         // Clear the port of messages
  310.         while (msg = GetMsg(port)) {
  311.             ReplyMsg(msg);
  312.         }
  313.  
  314.         // Closedown quitting port
  315.         DeleteMsgPort(port);
  316.  
  317.         // Clear and Delete port stop Forbid()
  318.         Permit();
  319.     }
  320. }
  321.  
  322. static BOOL Replace(void)
  323. {
  324.     // Allocate the jump table
  325.     SWTEntry = AllocMem(sizeof(JmpEntry), 0);
  326.     if (SWTEntry) {
  327.         // Replacement Forbid()
  328.         Forbid();
  329.  
  330.         // Replace the function with pointer to jump table
  331.         old_SetWindowTitles = SetFunction((struct Library *)IntuitionBase,
  332.                                             SWTOffset, (ULONG (*)())SWTEntry);
  333.  
  334.         // Setup the jump table
  335.         SWTEntry->Instr = JMPINSTR;
  336.         SWTEntry->Func = new_SetWindowTitles;
  337.  
  338.         // Clear the cpu's cache so the execution cache is valid
  339.         CacheClearU();
  340.  
  341.         // Stop the replacement Forbid()
  342.         Permit();
  343.  
  344.         return TRUE;
  345.     } else {
  346.         return FALSE;
  347.     }
  348. }
  349.  
  350. static void Restore(void)
  351. {
  352.     BOOL my_table;
  353.     ULONG (*func)();
  354.  
  355.     // Fix back Forbid()
  356.     Forbid();
  357.  
  358.     // Put old pointer back and get current pointer at same time
  359.     func = SetFunction((struct Library *)IntuitionBase, SWTOffset,
  360.                             (ULONG (*)())old_SetWindowTitles);
  361.  
  362.     // Check to see if the pointer we get back is ours
  363.     if ((JmpEntry *)func != SWTEntry) {
  364.         // If not, leave jump table in place
  365.         my_table = FALSE;
  366.         SetFunction((struct Library *)IntuitionBase, SWTOffset,
  367.                     func);
  368.         SWTEntry->Func = old_SetWindowTitles;
  369.     } else {
  370.         // If so, free the jump table
  371.         my_table = TRUE;
  372.         FreeMem(SWTEntry, sizeof(JmpEntry));
  373.     }
  374.  
  375.     // Clear the cpu's cache so the execution cache is valid
  376.     CacheClearU();
  377.  
  378.     // Stop fix back Forbid()
  379.     Permit();
  380.  
  381.     // Let the user know if the jump table couldn't be freed
  382.     if (!my_table) {
  383.         DisplayBeep(NULL);
  384.     }
  385.  
  386.     // Wait 5 seconds to try and guarantee that all tasks have
  387.     // finished executing inside my replacement function before
  388.     // quitting.  There's no real way to guarantee, though.
  389.     Delay(250);
  390. }
  391.  
  392. static void __saveds __asm new_SetWindowTitles(
  393.                             register __a0 struct Window *window,
  394.                             register __a1 UBYTE *win_title,
  395.                             register __a2 UBYTE *scr_title,
  396.                             register __a6 struct Library *lib)
  397. {
  398.     // try to make sure only the Workbench title bar gets fixed
  399.       
  400.         // compares the title bar to 'A#??Chip-RAM'
  401.         // which matches 'Amiga Workbench (#??.)#??.??? Chip-RAM#??' 
  402.         // (the original Workbench title bar's beginning in German locale)
  403.         
  404.         // (you must change this to the English or whatever applicable counterpart)
  405.         // (to make this work again with the English/your given non-German locale)
  406.         
  407.         if (scr_title && (scr_title != (UBYTE *)0xffffffff) &&
  408.             (*scr_title == 'A') && strstr(scr_title, "Chip-RAM")) {
  409.         ULONG i = 0;
  410.         char ch;
  411.  
  412.         // Set last_str to nothing
  413.         *last_str = 0;
  414.  
  415.         // Add in the memory parts
  416.         while (ch = toupper(memorder_str[i])) {
  417.             switch (ch) {
  418.                 case 'C':
  419.                     if (!labels_after) {
  420.                         strcat(last_str, chip_str);
  421.                     }
  422.                     NumberToString(AvailMem(MEMF_CHIP));
  423.                     strcat(last_str, num_buf);
  424.                     if (labels_after) {
  425.                         strcat(last_str, chip_str);
  426.                     }
  427.                     break;
  428.                 case 'F':
  429.                     if (!labels_after) {
  430.                         strcat(last_str, fast_str);
  431.                     }
  432.                     NumberToString(AvailMem(MEMF_FAST));
  433.                     strcat(last_str, num_buf);
  434.                     if (labels_after) {
  435.                         strcat(last_str, fast_str);
  436.                     }
  437.                     break;
  438.                 case 'P':
  439.                     if (!labels_after) {
  440.                         strcat(last_str, public_str);
  441.                     }
  442.                     NumberToString(AvailMem(MEMF_PUBLIC));
  443.                     strcat(last_str, num_buf);
  444.                     if (labels_after) {
  445.                         strcat(last_str, public_str);
  446.                     }
  447.                     break;
  448.                 case 'T':
  449.                     if (!labels_after) {
  450.                         strcat(last_str, total_str);
  451.                     }
  452.                     NumberToString(AvailMem(0));
  453.                     strcat(last_str, num_buf);
  454.                     if (labels_after) {
  455.                         strcat(last_str, total_str);
  456.                     }
  457.                     break;
  458.                 case 'V':
  459.                     if (VMMBase) {
  460.                         if (!labels_after) {
  461.                             strcat(last_str, virtual_str);
  462.                         }
  463.                         NumberToString(AvailVMem(0));
  464.                         strcat(last_str, num_buf);
  465.                         if (labels_after) {
  466.                             strcat(last_str, virtual_str);
  467.                         }
  468.                     }
  469.                     break;
  470.                 case 'R':
  471.                     if (RetinaBase) {
  472.                         if (!labels_after) {
  473.                             strcat(last_str, retina_str);
  474.                         }
  475.                         NumberToString(Retina_AvailMem(0));
  476.                         strcat(last_str, num_buf);
  477.                         if (labels_after) {
  478.                             strcat(last_str, retina_str);
  479.                         }
  480.                     }
  481.                     break;
  482.             }
  483.             i++;
  484.         }
  485.         strcat(last_str, suffix_str);
  486.         old_SetWindowTitles(window, win_title, mem_str, lib);
  487.     }
  488.         else    // leave other window's titles untouched
  489.         {
  490.             old_SetWindowTitles(window, win_title, scr_title, lib);
  491.     }
  492. }
  493.  
  494. /*
  495.  * Convert the number to a string in the format the user specified.
  496.  * The string generated is 0 terminated.
  497.  *
  498.  * Uses global variables: buff_ptr, num_buff
  499.  *
  500.  */
  501.  
  502. static void NumberToString(ULONG number)
  503. {
  504.     number /= units;
  505.     if (sep1000) {
  506.         buff_ptr = num_buf;
  507.         format_number(number);
  508.         *buff_ptr = 0;
  509.     } else {
  510.         stcul_d(num_buf, number);
  511.     }
  512. }
  513.  
  514. // Functions below use recursive calls, so take heed when changing anything within
  515. // 'format_number' or 'no_lead_triple' (danger of trashing unallocated memory when the
  516. // string buffer boundary is not respected)
  517.  
  518. static void format_number(ULONG number)
  519. {
  520.     if (number > 1000) {
  521.         format_number(number / 1000);
  522.         lead_triple(number % 1000);
  523.     } else {
  524.         no_lead_triple(number);
  525.     }
  526. }
  527.  
  528. static void no_lead_triple(ULONG number)
  529. {
  530.     if (number > 10) {
  531.         no_lead_triple(number / 10);
  532.         *buff_ptr++ = ((number % 10) | 0x30);
  533.     } 
  534.         //Gwardar begin
  535.         else if (number == 10) { 
  536.                 *buff_ptr++ = (1 | 0x30); // fixes numeric display bug
  537.                 *buff_ptr++ = (0 | 0x30); // 
  538.         }
  539.         //Gwardar end
  540.         else  // if (number < 10) // removed by Gwardar (smaller code, faster)
  541.         {
  542.         *buff_ptr++ = (number | 0x30);
  543.     }
  544. }
  545.  
  546. static void lead_triple(ULONG number)
  547. {
  548.     *buff_ptr++ = comma;
  549.     *buff_ptr++ = ((number / 100) | 0x30);
  550.     number %= 100;
  551.     *buff_ptr++ = ((number / 10) | 0x30);
  552.     number %= 10;
  553.     *buff_ptr++ = (number | 0x30);
  554. }
  555.